<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <link rel="icon" href="images/favicon.ico" type="image/x-icon"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>影子AI 对话助手</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        /* 自定义滚动条样式 */
        ::-webkit-scrollbar {
            width: 6px;
            height: 6px;
        }
        ::-webkit-scrollbar-track {
            background: #f1f1f1;
            border-radius: 3px;
        }
        ::-webkit-scrollbar-thumb {
            background: #888;
            border-radius: 3px;
        }
        ::-webkit-scrollbar-thumb:hover {
            background: #555;
        }
    </style>
</head>
<body class="bg-gray-50 min-h-screen flex text-gray-800">
    <!-- 左侧边栏 -->
    <div class="w-[260px] bg-white border-r border-gray-200 flex flex-col h-screen">
        <!-- 顶部Logo区域 -->
        <div class="p-4 border-b border-gray-200">
            <div class="flex items-center space-x-2">
                <img src="../images/favicon.ico" alt="Logo" class="w-8 h-8">
                <span class="text-xl font-semibold">影子AI助手</span>
            </div>
        </div>

        <!-- 新对话按钮 -->
        <div class="p-4">
            <button class="w-full bg-[#2563eb] text-white rounded-lg px-4 py-3 hover:bg-blue-600 transition-colors flex items-center justify-center space-x-2">
                <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                    <path fill-rule="evenodd" d="M10 3a1 1 0 011 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H4a1 1 0 110-2h5V4a1 1 0 011-1z" clip-rule="evenodd" />
                </svg>
                <span>新对话</span>
            </button>
        </div>

        <!-- 对话历史 -->
        <div class="flex-1 overflow-y-auto p-2">
            <div class="space-y-1">
                <div class="text-sm text-gray-500 px-3 py-2 mb-2">历史对话</div>
                <button class="w-full text-left px-3 py-2 rounded-lg hover:bg-gray-100 transition-colors flex items-center space-x-3">
                    <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
                    </svg>
                    <span class="text-sm">昨天的编程讨论</span>
                </button>
                <button class="w-full text-left px-3 py-2 rounded-lg hover:bg-gray-100 transition-colors flex items-center space-x-3">
                    <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
                    </svg>
                    <span class="text-sm">Spring AI 问题</span>
                </button>
            </div>
        </div>

        <!-- 底部设置 -->
        <div class="border-t border-gray-200 p-4">
            <button class="w-full text-left px-3 py-2 rounded-lg hover:bg-gray-100 transition-colors flex items-center space-x-3">
                <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
                </svg>
                <span>设置</span>
            </button>
        </div>
    </div>

    <!-- 主内容区 -->
    <div class="flex-1 flex flex-col h-screen">
        <!-- 顶部标题栏 -->
        <div class="border-b border-gray-200 p-4">
            <h1 class="text-xl font-semibold">新对话</h1>
        </div>

        <!-- 聊天容器 -->
        <div id="chat-container" class="flex-1 overflow-y-auto p-4 space-y-6">
            <!-- 消息容器基础样式 -->
            <div id="sub-chat-container" class="max-w-3xl mx-auto px-4 space-y-6">
                <!-- AI消息示例 -->
                <div class="ai-message flex items-start space-x-4">
                    <div class="flex-shrink-0 w-8 h-8 rounded-full bg-blue-100 flex items-center justify-center">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-blue-600" viewBox="0 0 20 20" fill="currentColor">
                            <path d="M2 10a8 8 0 018-8v8h8a8 8 0 11-16 0z" />
                            <path d="M12 2.252A8.014 8.014 0 0117.748 8H12V2.252z" />
                        </svg>
                    </div>
                    <div class="flex-1">
                        <div class="bg-white rounded-lg px-4 py-3 shadow-sm">
                            <span class="text-gray-800">主人您好，我是您的AI助手，除了传统大模型的对话能力，我还可以做以下事情：<br/>
                            （1）访问数据库中的数据，比如查询、修改等。<br/>
                            （2）访问文件系统，比如读取、写入等。<br/>
                            （3）...
                            </span>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- 输入区域 -->
        <div class="border-t border-gray-200 p-4 bg-white">
            <div class="max-w-3xl mx-auto">
                <div class="flex items-end space-x-2">
                    <div class="flex-1 bg-white rounded-lg border border-gray-300 focus-within:border-blue-500 focus-within:ring-1 focus-within:ring-blue-500 transition-all">
                        <input type="text" id="message-input"
                            class="w-full px-4 py-3 bg-transparent outline-none"
                            placeholder="输入您的问题...">
                    </div>
                    <button id="send-button"
                            class="bg-[#2563eb] text-white px-6 py-3 rounded-lg hover:bg-blue-600 transition-colors flex items-center space-x-2">
                        <span>发送</span>
                        <svg id="loading-spinner" class="hidden w-4 h-4 animate-spin" viewBox="0 0 24 24">
                            <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
                            <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path>
                        </svg>
                    </button>
                </div>
                <div class="mt-2 text-xs text-gray-500 text-center">
                    基于 Spring AI 的流式对话系统
                </div>
            </div>
        </div>
    </div>

<script>
    // 获取HTML元素
    const chatContainer = document.getElementById('chat-container');
    const subChatContainer = document.getElementById('sub-chat-container');

    const messageInput = document.getElementById('message-input');
    const sendButton = document.getElementById('send-button');
    const loadingSpinner = document.getElementById('loading-spinner');

    // 发送消息处理
    /**
     * 处理发送消息的函数
     * 该函数被调用时，会获取输入框中的消息，并将其发送出去
     */
    function handleSend() {
        // 获取消息输入框中的内容，并去除前后空格
        const message = messageInput.value.trim();
        // 如果消息为空，则不执行后续操作
        if (!message) return;

        // 添加用户消息到聊天容器
        addMessage(message, 'user');
        // 清空消息输入框
        messageInput.value = '';

        // 构建API URL
        const apiUrl = new URL('http://localhost:8889/ollama/chat-client/generate_stream');
        // 添加请求参数
        apiUrl.searchParams.append('id', '01');
        apiUrl.searchParams.append('prompt', message);

        // 显示加载状态
        sendButton.disabled = true;
        loadingSpinner.classList.remove('hidden');

        // 创建EventSource连接
        const eventSource = new EventSource(apiUrl);
        let aiMessageElement = null;

        // 处理接收到的消息
        eventSource.onmessage = (event) => {
            try {
                // 解析接收到的数据
                const data = JSON.parse(event.data);
                console.log(data);
                const content = data.result?.output?.text || '';
                const finishReason = data.result?.metadata?.finishReason;

                // 创建消息容器（如果不存在）
                if (!aiMessageElement) {
                    aiMessageElement = addMessage('', 'ai');
                }

                // 追加内容到消息容器
                if (content) {
                    aiMessageElement.querySelector('.message-content').textContent += content;
                    autoScroll();
                }

                // 处理结束
                if (finishReason === 'STOP') {
                    eventSource.close();
                    sendButton.disabled = false;
                    loadingSpinner.classList.add('hidden');
                }
            } catch (error) {
                console.error('解析错误:', error);
            }
        };

        // 处理连接错误
        eventSource.onerror = (error) => {
            console.error('连接错误:', error);
            eventSource.close();
            sendButton.disabled = false;
            loadingSpinner.classList.add('hidden');
            //addMessage('对话连接异常，请重试', 'ai', true);
        };
    }

    // 添加消息到容器
    /**
     * 添加消息到聊天容器的函数
     * @param {string} content 消息内容
     * @param {string} type 消息类型，'user' 或 'ai'
     * @param {boolean} isError 是否为错误消息
     * @returns {HTMLElement} 返回创建的消息元素
     */
    function addMessage(content, type, isError = false) {


        const messageDiv = document.createElement('div');
        messageDiv.className = `${type}-message flex items-start space-x-4`;

        if (type === 'ai') {
            // 创建AI头像
            const avatarDiv = document.createElement('div');
            avatarDiv.className = 'flex-shrink-0 w-8 h-8 rounded-full bg-blue-100 flex items-center justify-center';
            const avatarSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            avatarSvg.setAttribute('class', 'h-5 w-5 text-blue-600');
            avatarSvg.setAttribute('viewBox', '0 0 20 20');
            avatarSvg.setAttribute('fill', 'currentColor');
            avatarSvg.innerHTML = `
                <path d="M2 10a8 8 0 018-8v8h8a8 8 0 11-16 0z" />
                <path d="M12 2.252A8.014 8.014 0 0117.748 8H12V2.252z" />
            `;
            avatarDiv.appendChild(avatarSvg);
            messageDiv.appendChild(avatarDiv);
        }

        const contentDiv = document.createElement('div');
        contentDiv.className = 'flex-1';

        const bubble = document.createElement('div');
        bubble.className = type === 'user'
            ? 'bg-[#2563eb] text-white px-4 py-3 rounded-lg shadow-sm ml-auto max-w-full w-fit'
            : `bg-white px-4 py-3 rounded-lg shadow-sm ${isError ? 'text-red-500' : 'text-gray-800'}`;

        const contentSpan = document.createElement('span');
        contentSpan.className = 'message-content';
        contentSpan.textContent = content;

        bubble.appendChild(contentSpan);
        contentDiv.appendChild(bubble);
        messageDiv.appendChild(contentDiv);
        //chatContainer.appendChild(messageDiv);
        subChatContainer.appendChild(messageDiv);

        autoScroll();
        return bubble;
    }

    // 自动滚动到底部
    /**
     * 自动滚动聊天容器到底部的函数
     */
    function autoScroll() {
        chatContainer.scrollTop = chatContainer.scrollHeight;
    }

    // 事件监听
    // 点击发送按钮时，调用handleSend函数
    sendButton.addEventListener('click', handleSend);
    // 消息输入框按下回车键时，调用handleSend函数
    messageInput.addEventListener('keypress', (e) => {
        if (e.key === 'Enter' && !e.shiftKey) {
            e.preventDefault();
            handleSend();
        }
    });
</script>
</body>
</html>
